package services;

import helpers.ConsoleConstants;
import helpers.ConsoleUtils;

import java.io.BufferedReader;
import java.io.BufferedWriter;
import java.io.File;
import java.io.FileNotFoundException;
import java.io.FileReader;
import java.io.FileWriter;
import java.io.IOException;
import java.net.MalformedURLException;
import java.net.URISyntaxException;
import java.net.URL;
import java.util.ArrayList;
import java.util.Date;
import java.util.List;

import org.apache.commons.io.FilenameUtils;
import org.apache.http.client.utils.URIBuilder;

import models.Company;
import models.Project;
import models.Resource;
import models.ResourceType;
import models.Setting;

public class TestSuiteService extends ResourceService {

	public static final String TEST_SUITE_FILE_EXTENSION = ".txt";

	private final ProjectService projectService = ProjectService.getService();
	private final SettingService settingService = SettingService.getService();

	private static TestSuiteService service;

	// Singleton pattern
	private TestSuiteService() {
	}

	public static TestSuiteService getService() {
		if (service == null) {
			service = new TestSuiteService();
		}
		return service;
	}

	public Resource getTestSuite(long testSuiteId) {
		return Resource.find.where().eq("type", ResourceType.TestSuite).idEq(testSuiteId).findUnique();
	}

	public Resource getTestSuite(Project project, String testSuiteName) {
		Resource testSuite = null;
		List<Resource> testSuites = Resource.findResourcesByProject(project, ResourceType.TestSuite);
		if (testSuites != null && !testSuites.isEmpty()) {
			for (Resource currentTestSuite : testSuites) {
				if (currentTestSuite.getName().equalsIgnoreCase(testSuiteName)) {
					testSuite = currentTestSuite;
					break;
				}
			}
		}
		return testSuite;
	}

	public Resource saveTestSuite(Resource testSuite) {
		return saveTestSuite(testSuite, null);
	}

	public Resource saveTestSuite(Resource testSuite, String content) {
		Resource result = testSuite;
		if (testSuite.getId() <= 0) {
			result = createTestSuite(testSuite);
		} else {
			result = updateTestSuite(testSuite);
		}
		storeTestSuiteFile(result, content);
		return result;
	}

	private Resource createTestSuite(Resource testSuite) {
		Date currentDate = new Date();
		testSuite.setType(ResourceType.TestSuite);
		testSuite.setCreatedDate(currentDate);
		testSuite.setLastModifiedDate(currentDate);
		testSuite.save();
		return testSuite;
	}

	private Resource updateTestSuite(Resource testSuite) {
		testSuite.setLastModifiedDate(new Date());
		testSuite.save();
		return testSuite;
	}

	public void deleteTestSuites(Project project) {
		List<Resource> testSuites = Resource.findResourcesByProject(project, ResourceType.TestSuite);
		for (Resource testSuite : testSuites) {
			testSuite.delete();
		}
	}

	public String getTestSuiteFileContent(Resource testSuite) {
		String content = "";
		if (testSuite != null && testSuite.getResourcePath() != null) {
			File configFile = new File(testSuite.getResourcePath());
			if (configFile.exists()) {
				BufferedReader reader = null;
				try {
					reader = new BufferedReader(new FileReader(configFile));
					StringBuilder builder = new StringBuilder();
					String line = reader.readLine();

					while (line != null) {
						builder.append(line).append("\n");
						line = reader.readLine();
					}
					content = builder.toString();
				} catch (Exception e) {
					// TODO Auto-generated catch block
					e.printStackTrace();
				} finally {
					if (reader != null) {
						try {
							reader.close();
						} catch (IOException e) {
							// TODO Auto-generated catch block
							e.printStackTrace();
						}
					}
				}
			}
		}
		return content;
	}

	private void storeTestSuiteFile(Resource testSuite, String content) {
		if (testSuite != null && content != null) {
			BufferedWriter writer = null;
			try {
				File testSuiteFile = null;
				if (testSuite.getResourcePath() == null) {
					File directory = new File(getTestSuitesDirectory(testSuite.getProject()));
					if (!directory.exists()) {
						directory.mkdirs();
					}

					testSuiteFile = new File(directory, getTestSuiteFileName(testSuite));

					testSuite.setResourcePath(testSuiteFile.getAbsolutePath());
					testSuite.save();
				} else {
					testSuiteFile = new File(testSuite.getResourcePath());
				}

				if (testSuiteFile.exists()) {
					// Keep backup one last revision only
					File backupFile = new File(testSuite.getResourcePath() + ".bak");
					if (backupFile.exists()) {
						backupFile.delete();
					}
					testSuiteFile.renameTo(backupFile);
				}

				writer = new BufferedWriter(new FileWriter(testSuiteFile));
				writer.write(content.replaceAll("\r\n|\r", "\n"));
			} catch (FileNotFoundException e) {
				// TODO Auto-generated catch block
				e.printStackTrace();
			} catch (IOException e) {
				// TODO Auto-generated catch block
				e.printStackTrace();
			} finally {
				if (writer != null) {
					try {
						writer.close();
					} catch (IOException e) {
						// TODO Auto-generated catch block
						e.printStackTrace();
					}
				}
			}
		}
	}

	private String getTestSuiteFileName(Resource testSuite) {
		return testSuite.getId() + TEST_SUITE_FILE_EXTENSION;
	}

	public String getTestSuitesDirectory(Project project) {
		String directory = null;
		if (project != null) {
			directory = ConsoleUtils.getPath(new String[] { projectService.getProjectDirectory(project), ConsoleConstants.TEST_SUITES_DIRECTORY });
		}
		return directory;
	}

	public List<String> getLibraries(Company company) {
		List<String> libraries = new ArrayList<String>();
		Setting setting = settingService.getSetting(Setting.CUSTOMERS_ROOT_DIRECTORY);
		File directory = new File(setting.getStringValue() + ConsoleConstants.PATH_SEPARATOR + ConsoleConstants.COMMON_DIRECTORY + ConsoleConstants.PATH_SEPARATOR + ConsoleConstants.LIBRARY_DIRECTORY);
		if (directory.isDirectory() && directory.exists()) {
			for (File file : directory.listFiles()) {
				if (file.getName().endsWith(".py")) {
					libraries.add(file.getName().substring(0, file.getName().length() - 3));
				}
			}
		}
		if (company != null) {
			directory = new File(setting.getStringValue() + ConsoleConstants.PATH_SEPARATOR + company.getCompanyId() + ConsoleConstants.PATH_SEPARATOR + ConsoleConstants.LIBRARY_DIRECTORY);
			if (directory.isDirectory() && directory.exists()) {
				for (File file : directory.listFiles()) {
					if (file.getName().endsWith(".py")) {
						libraries.add(file.getName().substring(0, file.getName().length() - 3));
					}
				}
			}
		}
		return libraries;
	}

	public URL getTestExecuteURL(Project project, String testSuiteName, Resource config) throws MalformedURLException, URISyntaxException {
		URIBuilder builder = new URIBuilder(settingService.getSetting(Setting.TEST_EXECUTION_URL).getStringValue());
		builder.addParameter("companyid", ConsoleUtils.getCompany().getCompanyId());
		builder.addParameter("projectid", Long.toString(project.getId()));
		builder.addParameter("suite", testSuiteName);
		builder.addParameter("variablefile", FilenameUtils.getName(config.getResourcePath()));
		return builder.build().toURL();
	}

	public String getTestSuiteContentTemplate() {
		StringBuilder result = new StringBuilder();
		result.append("*** Settings ***").append("\n");
		result.append("# The test suite settings section").append("\n\n\n");

		result.append("*** Variables  ***").append("\n");
		result.append("# The test suite variables section").append("\n\n\n");

		result.append("*** Test Cases  ***").append("\n");
		result.append("# The test suite test cases section").append("\n\n\n");

		result.append("*** Keywords  ***").append("\n");
		result.append("# The test suite keywords section").append("\n\n");
		return result.toString();
	}

}
